/*
 * 文件名称:          ProxySessionFactory.java
 * 版权所有@ 2016——2017 无锡聆音科技有限公司，保留所有权利
 * 时间:             2016年7月27日 下午9:21:11
 */
package com.lingyin.database.transaction.hibernate;

import java.io.Serializable;
import java.sql.Connection;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;

import javax.naming.NamingException;
import javax.naming.Reference;

import org.hibernate.Cache;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionBuilder;
import org.hibernate.SessionFactory;
import org.hibernate.StatelessSession;
import org.hibernate.StatelessSessionBuilder;
import org.hibernate.TypeHelper;
import org.hibernate.engine.spi.FilterDefinition;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.metadata.CollectionMetadata;
import org.hibernate.stat.Statistics;
import org.springframework.core.InfrastructureProxy;

/**
 *  该类为代理hibernate的sessionfactory类。
 *  在该类中实际保存做需要使用的sessionfactory实现，
 *  在需要动态改变sessionfactory的实现的时候，需要首先获取IProxySessionFactoryBuilder
 *  实例，通过该实例修改相关的配置设置，然后再调用resetSessionFactory方法即可替换原有
 *  的sessionfactory实现。
 * 
 * @项目        hibernate.database.transaction
 * 
 * @作者:       关宏新
 * 
 * @日期:       2016年7月27日
 * 
 * @负责人:    关宏新
 * 
 * @负责小组:   聆音项目组
 * 
 */
public class ProxySessionFactory implements SessionFactory, IProxySessionFactory, InfrastructureProxy
{
    // 实际的sessionfactory对象
    private SessionFactory mainSessionFactory;
    // sessionfactory构建器
    private IProxySessionFactoryBuilder sessionBuilder;
    // 定时清除无用的sessionfactory，以免导致内存泄漏。
    private Timer timer = new Timer(true);
    // 无用sessionfactory清除的延时时间，及在sessionfactory无用后，多少时间后被清除，默认为30分钟后清除。
    private long delay = 30 * 60 * 1000L;
    

    /**
     * 
     */
    public ProxySessionFactory()
    {
    }    

    
    /**
     * @return 返回 sessionBuilder
     */
    public IProxySessionFactoryBuilder getSessionBuilder()
    {
        return sessionBuilder;
    }


    /**
     * @param sessionBuilder 设置 sessionBuilder
     */
    public void setSessionBuilder(IProxySessionFactoryBuilder sessionBuilder)
    {
        this.sessionBuilder = sessionBuilder;
        mainSessionFactory = sessionBuilder.getSessionFactory();
    }
    
    /**
     * 
     *(non-Javadoc)
     * @see com.sugon.database.transaction.hibernate.IProxySessionFactory#resetSessionFactory()
     *
     */
    public void resetSessionFactory()
    {
        try
        {
            sessionBuilder.afterPropertiesSet();
            SessionFactory oldSessionFactory;
            synchronized(mainSessionFactory)    // 锁定对象，以免被线程改变
            {
                oldSessionFactory = mainSessionFactory;
                mainSessionFactory = sessionBuilder.getSessionFactory();
            }
            releaseOldSessionFactory(oldSessionFactory);
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }        
    }

    /**
     * @param delay 设置 delay
     */
    public void setDelay(long delay)
    {
        this.delay = delay;
    }

    /**
     * 
     * @param sessionFactory
     */
    private void releaseOldSessionFactory(SessionFactory sessionFactory)
    {
        TimerTask task = new DisposeSessionFactory(sessionFactory);
        timer.schedule(task, delay);
    }

    /**
     * @return 返回 mainSessionFactory
     */
    public SessionFactory getMainSessionFactory()
    {
        return mainSessionFactory;
    }

    /**
     * @param mainSessionFactory 设置 mainSessionFactory
     */
    public void setMainSessionFactory(SessionFactory mainSessionFactory)
    {
        this.mainSessionFactory = mainSessionFactory;
    }

    /**
     * 
     *(non-Javadoc)
     * @see javax.naming.Referenceable#getReference()
     *
     */    
    public Reference getReference() throws NamingException
    {
        return mainSessionFactory.getReference();
    }

    /**
     * 
     *(non-Javadoc)
     * @see org.hibernate.SessionFactory#getSessionFactoryOptions()
     *
     */
    public SessionFactoryOptions getSessionFactoryOptions()
    {
        return mainSessionFactory.getSessionFactoryOptions();
    }

    /**
     * 
     *(non-Javadoc)
     * @see org.hibernate.SessionFactory#withOptions()
     *
     */
    public SessionBuilder withOptions()
    {
        return mainSessionFactory.withOptions();
    }

    /**
     * 
     *(non-Javadoc)
     * @see org.hibernate.SessionFactory#openSession()
     *
     */
    public Session openSession() throws HibernateException
    {
        return mainSessionFactory.openSession();
    }

    /**
     * 
     *(non-Javadoc)
     * @see org.hibernate.SessionFactory#getCurrentSession()
     *
     */
    public Session getCurrentSession() throws HibernateException
    {
        return mainSessionFactory.getCurrentSession();
    }

    /**
     * 
     *(non-Javadoc)
     * @see org.hibernate.SessionFactory#withStatelessOptions()
     *
     */
    public StatelessSessionBuilder withStatelessOptions()
    {
        return mainSessionFactory.withStatelessOptions();
    }

    /**
     * 
     *(non-Javadoc)
     * @see org.hibernate.SessionFactory#openStatelessSession()
     *
     */
    public StatelessSession openStatelessSession()
    {
        return mainSessionFactory.openStatelessSession();
    }

    /**
     * 
     *(non-Javadoc)
     * @see org.hibernate.SessionFactory#openStatelessSession(java.sql.Connection)
     *
     */
    public StatelessSession openStatelessSession(Connection connection)
    {
        return mainSessionFactory.openStatelessSession(connection);
    }

    /**
     * 
     *(non-Javadoc)
     * @see org.hibernate.SessionFactory#getClassMetadata(java.lang.Class)
     *
     */
    public ClassMetadata getClassMetadata(Class entityClass)
    {
        return mainSessionFactory.getClassMetadata(entityClass);
    }

    /**
     * 
     *(non-Javadoc)
     * @see org.hibernate.SessionFactory#getClassMetadata(java.lang.String)
     *
     */
    public ClassMetadata getClassMetadata(String entityName)
    {
        return mainSessionFactory.getClassMetadata(entityName);
    }

    /**
     * 
     *(non-Javadoc)
     * @see org.hibernate.SessionFactory#getCollectionMetadata(java.lang.String)
     *
     */
    public CollectionMetadata getCollectionMetadata(String roleName)
    {
        return mainSessionFactory.getCollectionMetadata(roleName);
    }

    /**
     * 
     *(non-Javadoc)
     * @see org.hibernate.SessionFactory#getAllClassMetadata()
     *
     */
    public Map<String, ClassMetadata> getAllClassMetadata()
    {
        return mainSessionFactory.getAllClassMetadata();
    }

    /**
     * 
     *(non-Javadoc)
     * @see org.hibernate.SessionFactory#getAllCollectionMetadata()
     *
     */
    public Map getAllCollectionMetadata()
    {
        return mainSessionFactory.getAllCollectionMetadata();
    }

    /**
     * 
     *(non-Javadoc)
     * @see org.hibernate.SessionFactory#getStatistics()
     *
     */
    public Statistics getStatistics()
    {
        return mainSessionFactory.getStatistics();
    }

    /**
     * 
     *(non-Javadoc)
     * @see org.hibernate.SessionFactory#close()
     *
     */
    public void close() throws HibernateException
    {
        mainSessionFactory.close();        
    }

    /**
     * 
     *(non-Javadoc)
     * @see org.hibernate.SessionFactory#isClosed()
     *
     */
    public boolean isClosed()
    {
        return mainSessionFactory.isClosed();
    }

    /**
     * 
     *(non-Javadoc)
     * @see org.hibernate.SessionFactory#getCache()
     *
     */
    public Cache getCache()
    {
        return mainSessionFactory.getCache();
    }

    /**
     * 
     *(non-Javadoc)
     * @see org.hibernate.SessionFactory#evict(java.lang.Class)
     *
     */
    public void evict(Class persistentClass) throws HibernateException
    {
        mainSessionFactory.evict(persistentClass);        
    }

    /**
     * 
     *(non-Javadoc)
     * @see org.hibernate.SessionFactory#evict(java.lang.Class, java.io.Serializable)
     *
     */
    public void evict(Class persistentClass, Serializable id) throws HibernateException
    {
        mainSessionFactory.evict(persistentClass, id);
    }

    /**
     * 
     *(non-Javadoc)
     * @see org.hibernate.SessionFactory#evictEntity(java.lang.String)
     *
     */
    public void evictEntity(String entityName) throws HibernateException
    {
        mainSessionFactory.evictEntity(entityName);
    }

    /**
     * 
     *(non-Javadoc)
     * @see org.hibernate.SessionFactory#evictEntity(java.lang.String, java.io.Serializable)
     *
     */
    public void evictEntity(String entityName, Serializable id) throws HibernateException
    {
        mainSessionFactory.evictEntity(entityName, id);
    }

    /**
     * 
     *(non-Javadoc)
     * @see org.hibernate.SessionFactory#evictCollection(java.lang.String)
     *
     */
    public void evictCollection(String roleName) throws HibernateException
    {
        mainSessionFactory.evictCollection(roleName);
    }

    /**
     * 
     *(non-Javadoc)
     * @see org.hibernate.SessionFactory#evictCollection(java.lang.String, java.io.Serializable)
     *
     */
    public void evictCollection(String roleName, Serializable id) throws HibernateException
    {
        mainSessionFactory.evictCollection(roleName, id);
    }

    /**
     * 
     *(non-Javadoc)
     * @see org.hibernate.SessionFactory#evictQueries(java.lang.String)
     *
     */
    public void evictQueries(String cacheRegion) throws HibernateException
    {
        mainSessionFactory.evictQueries(cacheRegion);
    }

    /**
     * 
     *(non-Javadoc)
     * @see org.hibernate.SessionFactory#evictQueries()
     *
     */
    public void evictQueries() throws HibernateException
    {
        mainSessionFactory.evictQueries();
    }

    /**
     * 
     *(non-Javadoc)
     * @see org.hibernate.SessionFactory#getDefinedFilterNames()
     *
     */
    public Set getDefinedFilterNames()
    {
        return mainSessionFactory.getDefinedFilterNames();
    }

    /**
     * 
     *(non-Javadoc)
     * @see org.hibernate.SessionFactory#getFilterDefinition(java.lang.String)
     *
     */
    public FilterDefinition getFilterDefinition(String filterName) throws HibernateException
    {
        return mainSessionFactory.getFilterDefinition(filterName);
    }

    /**
     * 
     *(non-Javadoc)
     * @see org.hibernate.SessionFactory#containsFetchProfileDefinition(java.lang.String)
     *
     */
    public boolean containsFetchProfileDefinition(String name)
    {
        return mainSessionFactory.containsFetchProfileDefinition(name);
    }

    /**
     * 
     *(non-Javadoc)
     * @see org.hibernate.SessionFactory#getTypeHelper()
     *
     */
    public TypeHelper getTypeHelper()
    {
        return mainSessionFactory.getTypeHelper();
    }
    
    /**
     * 
     *(non-Javadoc)
     * @see org.springframework.core.InfrastructureProxy#getWrappedObject()
     *
     */
    public Object getWrappedObject()
    {
        return mainSessionFactory;
    }
    
    /**
     * 
     *(non-Javadoc)
     * @see java.lang.Object#toString()
     *
     */
    public String toString()
    {
        return this.hashCode() + ",s=" + mainSessionFactory.hashCode();
    }
    
}
